package learn.sec;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.util.Arrays;

public class MessageDecryption {

    static Charset CHARSET = Charset.forName("utf-8");
    private static Logger logger = LoggerFactory.getLogger(MessageDecryption.class);

    private static final String appId = "wx8a4575c2cbfdb4b2";
    private static final String ivData = "WELOy1iDdxKX7xwsvtO2FQ==";
    private static final String sessionKey = "ltNwq7RkQUiT+yPK1L4GlA==";
    private static final String encryptedData = "lt6Q1qbDAxFDwgU7cV1N7aJUCyAzKVhi5cP9aPotnXsIK7JpG4O8E7qghM1n8AGmL8PLS1R0CXm2OZoBE6py8ZtXLM+ZfjBJpYOU9/NIZc2PRdh+GnJcGEgVAWf2q4fy2dgLuwbzF/rwzH/8cWHtaM/hn9jnEXiGGLZ068gqG0jrwco6mjmxLXMf7O6E/kdJ+zXiBduX7thC5KvEW99nWgJt434lbXNEMa0bKE/zNpN03A18XWuQK9Ofy7EBg+2T4FCq7rxSaYBZAYNKObUwKBzr+dovJf09tJOx5tkBXTzQDS+12BWEOCLsvpeEZ47AyNG5n6BNhbcBfQ1oOF1oiUyM8uzzW61GMstztxgC3YQOAF4WybWRTQnEtikzv56brV2BmLx88E1Fk+W8dsydRSnSlMBiPWh406SqPqDeK5Pdw29/vebnkuPL0OxWEO6f6jHp0WmQgz/Wj2c84+WcADoyiSMkyIHNxQd+6a7ntGE=";

    private static int recoverNetworkBytesOrder(byte[] orderBytes) {
        int sourceNumber = 0;
        for (int i = 0; i < 4; i++) {
            sourceNumber <<= 8;
            sourceNumber |= orderBytes[i] & 0xff;
        }
        return sourceNumber;
    }

    public static void main(String[] args) throws AesException {
        final String decrypt = decrypt(encryptedData);
        System.out.println(decrypt);
    }

    private static String decrypt(String text) throws AesException {
        byte[] original;
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec key_spec = new SecretKeySpec(Base64.decodeBase64(sessionKey), "AES");
            IvParameterSpec iv = new IvParameterSpec(Base64.decodeBase64(ivData));
            cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
            byte[] encrypted = Base64.decodeBase64(text);
            original = cipher.doFinal(encrypted);
        } catch (Exception e) {
            logger.error("MessageDecryption decrypt failed.", e);
            throw new AesException(AesException.DecryptAESError);
        }
        String xmlContent, from_corpid;
        try {
            byte[] bytes = PKCS7Encoder.decode(original);
            byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
            int xmlLength = recoverNetworkBytesOrder(networkOrder);
            xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
            from_corpid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
                    CHARSET);
        } catch (Exception e) {
            logger.error("MessageDecryption decrypt failed.", e);
            throw new AesException(AesException.IllegalBuffer);
        }
        if (!from_corpid.equals(appId)) {
            logger.error("MessageDecryption decrypt failed, corpid mismatches.");
            throw new AesException(AesException.ValidateCorpidError);
        }
        return xmlContent;
    }
}
